#if !defined(glib_g2_vector_h)
#define glib_g2_vector_h

#include <cmath>
#include "glib/operations.h"
#include "typelib/types.h"

namespace g2 {

template <typename T>
class basic_vector;

typedef basic_vector<double> vector;
typedef basic_vector<float> vectorf;
typedef basic_vector<long double> vectorl;

template <typename T>
class basic_vector {
public:
    T x, y;
public:
	static basic_vector<T> const nill; //(0,0) vector
public:
	typedef T * iterator;
	typedef const T * const_iterator;
public:
	T * begin()
		{ return &x; }
	const T * begin() const
		{ return &x; }
	T * end()
		{ return &y + 1; }
	const T * end() const
		{ return &y + 1; }
public:
	basic_vector()
		{ }
    basic_vector(T _x, T _y) 
		: x(_x), y(_y) { }
	template <class U> 
	basic_vector(const basic_vector<U> & v) 
		: x(T(v.x)), y(T(v.y)) { }
	template <class U> 
	basic_vector(const point<U> & v) 
		: x(T(v.x)), y(T(v.y)) { }
	basic_vector & zero() 
		{ x = y = 0; return * this; }
	operator point<T> () const
		{ return point<T>(x, y); }
public:
    basic_vector & operator += (const basic_vector<T> & v)
        { x += v.x; y += v.y; return * this; }
    basic_vector & operator -= (const basic_vector<T> & v)
        { x -= v.x; y -= v.y; return * this; }
    basic_vector & operator *= (T a)
        { x *= a; y *= a; return * this; }
    basic_vector & operator /= (T a)
        { x /= a; y /= a; return * this; }
	bool operator < (const basic_vector<T> & v) const
		{ return x < v.x && y < v.y; }
	bool operator <= (const basic_vector<T> & v) const
		{ return x <= v.x && y <= v.y; }
	bool operator == (const basic_vector<T> & v) const
		{ return x == v.x && y == v.y; }
	bool operator != (const basic_vector<T> & v) const
		{ return x != v.x || y != v.y; }
public:
	T & operator ()(int index)
		{ return * (&x + index); }
	const T & operator ()(int index) const
		{ return * (&x + index); }
	static int size() 
		{ return 2; }
public:
	/// returns vector orthogonal to this, having the same length;
	/// outer_product(*this, orthogonal()) = sqr(*this)
	basic_vector orthogonal() const
		{ return basic_vector(-y, x); }
	/// makes a non-zero vector of unit length
	basic_vector & normalize();
};

template <class T>
inline basic_vector<T> & basic_vector<T>::normalize()
{
	T length = abs(* this);
	if (length != 0)
		* this /= length;
	return * this;
}

/// this functor compares two vectors in lexicographic order
template <typename T>
struct lexi_less {
	bool operator () (basic_vector<T> const & lhs, basic_vector<T> const & rhs) const
		{ return lhs.x < rhs.x || lhs.x == rhs.x && lhs.y < rhs.y; }
};

//inline implementation

template <typename T>
basic_vector<T> const basic_vector<T>::nill(0, 0);

template <typename T>
inline basic_vector<T> operator + (const basic_vector<T> & a, const basic_vector<T> & b) {
	basic_vector<T> t(a);
    return t += b;
}

template <typename T>
inline basic_vector<T> operator - (const basic_vector<T> & a, const basic_vector<T> & b) {
	basic_vector<T> t(a);
    return t -= b;
}

//unary minus
template <typename T>
inline basic_vector<T> operator - (const basic_vector<T> & a) {
	return basic_vector<T>(-a.x, -a.y);
}

template <typename T>
inline basic_vector<T> operator * (const basic_vector<T> & v, T a) {
	basic_vector<T> t(v);
    return t *= a;
}

template <typename T>
inline basic_vector<T> operator * (T a, const basic_vector<T> & v) {
	basic_vector<T> t(v);
    return t *= a;
}

template <typename T>
inline basic_vector<T> operator / (const basic_vector<T> & v, T a) {
	basic_vector<T> t(v);
    return t /= a;
}

template <typename T, typename F>
inline basic_vector<T> rotate(const basic_vector<T> & v, F angle) {
	F cosa = cos(angle), sina = sin(angle);
	return basic_vector<T>(T(v.x * cosa - v.y * sina), T(v.x * sina + v.y * cosa)); 
}

} // g2

template <typename T>
inline T scalar_product(const g2::basic_vector<T> & v1, const g2::basic_vector<T> & v2) 
	{ return v1.x * v2.x + v1.y * v2.y; }

template <typename T>
inline T outer_product(const g2::basic_vector<T> & v1, const g2::basic_vector<T> & v2) 
	{ return v1.x * v2.y - v1.y * v2.x; }

template <typename T>
class squarer<g2::basic_vector<T> > {
	T s;
public:
	explicit squarer(const g2::basic_vector<T> & v) : s(scalar_product(v, v)) { }
	operator T () const { return s; }
};

template <typename T>
class absoluter<g2::basic_vector<T> > {
	T a;
public:
	explicit absoluter(const g2::basic_vector<T> & v) : a(::sqrt(sqr(v))) { }
	operator T () const { return a; }
};

#endif // glib_g2_vector_h
